using System;
using System.Collections;
using System.Text;
using System.Xml.Serialization;

namespace PaulRz.Util
{
	public abstract class Session
	{
		private string connector;
		private string templateName;
		public ILogger Logger = new ConsoleLogger();


		protected SessionReport report = new SessionReport();

		public string Connector
		{
			get { return connector; }
			set { connector = value; }
		}

		public string TemplateName
		{
			get { return templateName; }
			set { templateName = value; }
		}

		/// <summary>
		/// Adds passed attributes to the session. If object with given is allready exists, the old value will be overwritten.
		/// </summary>
		/// <param name="id">messageId or other "key"</param>
		/// <param name="attributes">Hashtable of values</param>
		/// <param name="secondsToExpire">Number of secodns to invalidate given record</param>
		public abstract void Add(string id, Hashtable attributes, int secondsToExpire);

		/// <summary>
		/// Adds passed attributes to the session. If object with given is allready exists, the old value will be overwritten.
		/// </summary>
		public abstract void AddAttribute(string id, string key, string value, int secondsToExpire);

		/// <summary>
		/// Returns specified message attribute from message with given id.
		/// If id or attribute name hasn't found the empy string would be returned
		/// </summary>
		/// <param name="id">messageId or other "key"</param>
		/// <param name="propertyName">attribute name</param>
		/// <returns></returns>
		public abstract string GetValue(string id, string propertyName);

		/// <summary>
		/// Returns a hashtable of all attributes from message with specified id
		/// </summary>
		public abstract Hashtable this[string id] { get; }

		public abstract bool Contains(string id);

		/// <summary>
		/// Cleans all expired ContextItems
		/// </summary>
		public abstract void Clean(object dummy);

		/// <summary>
		/// Returns count of messages in session
		/// </summary>
		/// <returns></returns>
		public abstract int GetSessionCount();

		/// <summary>
		/// Returns report of given session activity
		/// </summary>
		/// <returns></returns>
		public SessionReport GetReport()
		{
			return report;
		}

		/// <summary>
		/// Commits changes to the persistent storage (for persistent session)
		/// </summary>
		public abstract void Commit();
		
		public abstract void CleanAllSessions();

		public event ItemCleanedCallback OnClean;
		public event ItemCleanedCallback OnLog;
		public abstract void Remove(string sessionId);

		protected void OnCleanWrapper(SessionItem si)
		{
			if (si == null || String.IsNullOrEmpty(si.TemplateName))
				return;
			if (OnClean != null)
				OnClean(si);
		}

        /// <summary>
        /// Returns array of all sessions, containing specified propertyName = propertyValue
        /// </summary>
        /// <param name="propertyName">attribute name</param>
        /// <param name="propertyValue">attribute value</param>
        /// <returns></returns>
        public abstract SessionItem[] GetSessionsContaining(string propertyName, string propertyValue);
	}

	/// <summary>
	/// Contains information about given session item
	/// </summary>
	public class SessionItem
	{
		public string SessionId;
		public DateTime Expiration;
		public Hashtable Attributes;
		public string Connector;
		public string TemplateName;

		public string GetCRMXML()
		{
			StringBuilder sb = new StringBuilder();
			foreach (DictionaryEntry attribute in Attributes)
			{
				sb.Append(string.Format("<Attribute name=\"{0}\" value=\"{1}\" />\r\n", attribute.Key, attribute.Value));
			}

			string result = string.Format(
				@"<Message type=""triggedbysession"" session_id=""{0}"" id=""{1}"">
	<Item>{2}</Item>
</Message>", SessionId,
				Guid.NewGuid(), sb);

			return result;
		}
	}

	public delegate void ItemCleanedCallback(SessionItem item);

	[Serializable]
	public class SessionReport
	{
		public ulong Writes;
		public ulong Found;
		public ulong NotFound;


		public override string ToString()
		{
			return string.Format("Writes: {0}, Found: {1}, NotFound: {2}", Writes, Found, NotFound);
		}
	}
}